/*
 * Copyright 2010 Biz-e (info@biz-e.nl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.biz_e.gwt.baselib.ui.client.widgets;

import java.util.List;
import java.util.Vector;

import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;

/**
 * TODO: Write type comment
 * 
 * @author Joost A. Bloemsma
 */
public class PictureListBox extends Composite {
    private Grid main;
    private FlexTable list = new FlexTable();
    private Label captionLabel = new Label();
    private List<PictureListBoxItem<? extends Object>> items = new Vector<PictureListBoxItem<? extends Object>>();

    /**
     * Constructs a new PictureListBox instance
     */
    public PictureListBox() {
        main = new Grid(2, 1);
        main.setWidget(0, 0, captionLabel);
        main.setWidget(1, 0, list);
        this.initWidget(main);
    }

    /**
     * @param caption
     */
    public void setCaption(String caption) {
        captionLabel.setText(caption);
    }

    /**
     * @return the caption
     */
    public String getCaption() {
        return captionLabel.getText();
    }

    /**
     * Adds an item to the listbox at the specified position. If the passed
     * index is too high, it gets positioned at the end.
     * 
     * @param item
     * @param index
     * @return the resulting index.
     */
    public int addItem(PictureListBoxItem<? extends Object> item, int index) {
        if (item == null)
            throw new IllegalStateException("PictureListBoxItem cannot be null");
        if (items.contains(item))
            return this.getIndex(item);
        if (index >= items.size())
            return addItem(item);
        items.add(index, item);
        showItem(item, index);
        return index;
    }

    /**
     * Adds an item to the listbox at the end.
     * 
     * @param item
     * @return the resulting index.
     */
    public int addItem(PictureListBoxItem<? extends Object> item) {
        if (item == null)
            throw new IllegalStateException("PictureListBoxItem cannot be null");
        if (items.contains(item))
            return this.getIndex(item);
        if (items.add(item)) {
            int index = getIndex(item);
            showItem(item, index);
            return index;
        } else {
            return -1;
        }
    }

    /**
     * @param item
     * @return the index of the specified item
     */
    public int getIndex(PictureListBoxItem<? extends Object> item) {
        int i = items.indexOf(item);
        if (i >= 0)
            return i;
        // Item unknown
        if (this == item.getListBox()) {
            item.setListBox(null);
        }
        return -1;
    }

    private void showItem(PictureListBoxItem<? extends Object> item, int index) {
        int numOfRows = list.getRowCount();
        if (index < numOfRows) {
            list.insertRow(index);
        }
        list.setWidget(index, 0, new Label(item.getText()));
        list.setWidget(index, 1, item.getPicture());
    }

    /**
     * Represents an item on the listbox.
     * Contains text, a picture and data in the form of an object
     * 
     * @author Joost A. Bloemsma
     * @param <E>
     */
    public static class PictureListBoxItem<E extends Object> {
        private String text;
        private Image picture;
        private PictureListBox listBox;
        private E data;

        /**
         * Constructs a new PictureListBoxItem instance
         */
        public PictureListBoxItem() {
            super();
        }

        /**
         * Constructs a new PictureListBoxItem instance
         * 
         * @param data
         */
        public PictureListBoxItem(E data) {
            this(data.toString());
            this.data = data;
        }

        /**
         * Constructs a new PictureListBoxItem instance
         * 
         * @param text
         */
        public PictureListBoxItem(String text) {
            this(text, (Image) null);
        }

        /**
         * Constructs a new PictureListBoxItem instance
         * 
         * @param text
         * @param image
         */
        public PictureListBoxItem(String text, Image image) {
            this();
            this.setText(text);
            this.setPicture(image);
        }

        /**
         * Constructs a new PictureListBoxItem instance
         * 
         * @param text
         * @param resource
         */
        public PictureListBoxItem(String text, ImageResource resource) {
            this();
            this.setText(text);
            this.setPicture(resource);
        }

        /**
         * Constructs a new PictureListBoxItem instance
         * 
         * @param text
         * @param url
         */
        public PictureListBoxItem(String text, String url) {
            this();
            this.setText(text);
            this.setPicture(url);
        }

        /**
         * @return the text
         */
        public String getText() {
            return text;
        }

        /**
         * @param text
         *            the text to set
         */
        public void setText(String text) {
            this.text = text;
        }

        /**
         * @return the picture
         */
        public Image getPicture() {
            return picture;
        }

        /**
         * @param picture
         *            the picture to set
         */
        public void setPicture(Image picture) {
            this.picture = picture;
        }

        /**
         * @param resource
         */
        public void setPicture(ImageResource resource) {
            this.picture = new Image(resource);
        }

        /**
         * @param url
         */
        public void setPicture(String url) {
            this.picture = new Image(url);
        }

        /**
         * @return the index
         */
        public int getIndex() {
            if (listBox == null)
                return -1;
            return listBox.getIndex(this);
        }

        /**
         * @return the listBox
         */
        public PictureListBox getListBox() {
            return listBox;
        }

        /**
         * @param listBox
         *            the listBox to set
         */
        void setListBox(PictureListBox listBox) {
            this.listBox = listBox;
        }

        /**
         * @return the data
         */
        public E getData() {
            return data;
        }

        /**
         * @param data
         *            the data to set
         */
        public void setData(E data) {
            this.data = data;
        }

    }
}
